package org.ubc.cs410.disposal2020.server;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import javax.jdo.Transaction;

import org.ubc.cs410.disposal2020.Game;
import org.ubc.cs410.disposal2020.GameFactory;
import org.ubc.cs410.disposal2020.Garbage;
import org.ubc.cs410.disposal2020.NoActiveGameException;
import org.ubc.cs410.disposal2020.PMF;
import org.ubc.cs410.disposal2020.Player;
import org.ubc.cs410.disposal2020.Robot;
import org.ubc.cs410.disposal2020.client.GameService;
import org.ubc.cs410.disposal2020.client.dto.GarbageDto;
import org.ubc.cs410.disposal2020.client.dto.RobotDto;

import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserServiceFactory;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

public class GameServiceImpl extends RemoteServiceServlet implements
GameService {

	@Override
	public Map<String,String> listAvailableGames() {
		Map<String,String> games = new HashMap<String,String>();

		PersistenceManager pm = PMF.get().getPersistenceManager();

		try {
			Query query = pm.newQuery(Game.class);
			List<Game> allGames = (List<Game>) query.execute();
			for (Game g : allGames) {
				if (g.isWaiting()) {
					games.put(g.getSlug(),g.getPlayers().get(0).getUser());
				}
			}
		} finally {
			pm.close();
		}


		return games;
	}

	@Override
	public String isGameReady() {
		try {
			Game game = GameFactory.getCurrentGame();
			if (game.isActive()) {
				return game.getSlug();
			}
			return null;
		} catch (NoActiveGameException e) {
			return null;
		}
	}

	@Override
	public String joinGame(String selectedSlug) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try {
			Game game = GameFactory.getGameBySlug(selectedSlug,pm);
			if (game == null) {
				return null;
			} else if (!game.isWaiting()) {
				return null;
			}

			Player player = new Player(UserServiceFactory.getUserService().getCurrentUser().getEmail(),
					game);
			pm.makePersistent(player);
			game.addPlayer(player);

			game.start();

		} finally {
			pm.close();
		}
		return "success";
	}

	@Override
	public int getTurn() {
		Game game;
		try {
			game = GameFactory.getCurrentGame();
			for (Player p: game.getPlayers()) {
				for (Robot r: p.getRobots()) {
					// Still have movable robots means the turn is still in progress.
					if (r.isMovable() == true)
						return game.getTurn();
				}
			}
			// Start a new turn if there are no movable robots.
			if (game.nextTurn()) {
				return game.getTurn();
			} else {
				// Game ended
				PersistenceManager pm = PMF.get().getPersistenceManager();
				Game g = pm.getObjectById(Game.class, game.getId());
				g.end();
				return -1;
			}
		} catch (NoActiveGameException e) {
			return 0;
		}
	} 


	@Override
	public Set<GarbageDto> listAllGarbages() {
		int MaxGarbageAmount = 0;

		try {
			Game game = GameFactory.getCurrentGame();
			Set<GarbageDto> gs = new HashSet<GarbageDto>();
			for (Garbage g : game.getGarbage()) {
				GarbageDto gDto = new GarbageDto();
				gDto.setLatitude(g.getLatitude());
				gDto.setLongitude(g.getLongitude());
				gDto.setAmount(g.getAmount());
				gs.add(gDto);

				if (g.getAmount() > MaxGarbageAmount) {
					MaxGarbageAmount = g.getAmount();
				}
			}

			for (GarbageDto garbageDto : gs) {
				garbageDto.setMaxAmount(MaxGarbageAmount);
			}

			return gs;
		} catch (NoActiveGameException e) {
			return null;
		}    
	}
}
